﻿/**************************************************************
 *
 * 唯一标识：5a31531c-d877-470d-8a3b-d4cf8fe9bb2e
 * 命名空间：MediatR.Behaviors
 * 创建时间：2023/8/18 8:59:51
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：MediatR请求验证行为，用于在管道中统一处理请求参数校验
 *
 **************************************************************/

using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using FluentValidation;
using System.Linq;
using Sgr.Utilities;
using MediatR;

namespace Sgr.MediatR.Behaviors
{
    /// <summary>
    /// MediatR请求验证行为
    /// </summary>
    /// <typeparam name="TRequest">请求类型</typeparam>
    /// <typeparam name="TResponse">响应类型</typeparam>
    public class ValidatorBehavior<TRequest, TResponse>
        : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
    {
        private readonly ILogger<ValidatorBehavior<TRequest, TResponse>> _logger;
        private readonly IEnumerable<IValidator<TRequest>> _validators;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="validators">请求验证器集合</param>
        /// <param name="logger">日志记录器</param>
        public ValidatorBehavior(IEnumerable<IValidator<TRequest>> validators, ILogger<ValidatorBehavior<TRequest, TResponse>> logger)
        {
            _validators = validators;
            _logger = logger;
        }

        /// <summary>
        /// 处理请求并进行参数校验
        /// </summary>
        /// <param name="request">请求对象</param>
        /// <param name="next">下一个处理委托</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>响应对象</returns>
        public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
        {
#if DEBUG
            string typeName = TypeHelper.GetGenericTypeName(typeof(TRequest));
            _logger.LogInformation("MediatR 正在验证命令 {CommandType}", typeName);
#endif

            var failures = _validators
                .Select(v => v.Validate(request))
                .SelectMany(result => result.Errors)
                .Where(error => error != null)
                .ToList();

            if (failures.Count > 0)
            {
                string err = $"命令 {typeof(TRequest).Name} 的参数验证失败。";
#if DEBUG
                _logger.LogWarning("MediatR 验证错误: {@ValidationErrors}", failures);
                err += $"{string.Join("\n", failures.Select(f => f.ErrorMessage))}";
#endif
                throw new ValidationException(err, failures);
            }

            return await next();
        }
    }
}